package com.lapula.crazyface.util;

import java.io.File;
import java.nio.IntBuffer;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.hardware.Camera.Size;
import android.media.FaceDetector;
import android.media.FaceDetector.Face;
import android.os.AsyncTask;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;

import com.lapula.crazyface.D;
import com.lapula.crazyface.entity.CryEmotion;
import com.lapula.crazyface.entity.Emotion;
import com.lapula.crazyface.entity.Emotion.EmotionItem;

public class FaceEmotion {
	public static FaceEmotion I = new FaceEmotion();

	private Context context;

	private Emotion emotion = null;

	private boolean isDetecting = false;
	private List<MFace> faces = null;

	private final int THREAD_PRIORITY = 0;
	private final int NUMBER_OF_FACES = 10;

	private int cameraOrientation = 90;

	private Handler handler = new Handler() {

		@Override
		public void handleMessage(Message msg) {
			super.handleMessage(msg);
			Object[] objects = (Object[]) msg.obj;
			FaceTask task = new FaceTask((byte[]) objects[0], (Size) objects[1]);
			task.execute();
		}

	};

	private FaceEmotion() {
	}

	public static void init(Context c) {
		I.context = c;
		I.emotion = new CryEmotion(c);
	}

	public void render(Size size, IntBuffer mGLRgbBuffer, byte[] data) {
		if (context == null) {
			throw new RuntimeException("未指定context");
		}

		// 是否在识别
		if (!isDetecting) {
			// 否，则进行识别线程
			isDetecting = true;
			Message msg = new Message();
			msg.obj = new Object[] { data, size };
			handler.sendMessage(msg);
		}

		// 是否存在识别后的眼部位置
		Bitmap srcBitmap = ImageUtils.byte2Bitmap(data, size, Bitmap.Config.ARGB_8888);
		Bitmap rotatedBitmap = ImageUtils.rotateBitmap(srcBitmap, true, cameraOrientation);
		if (null != faces) {
			// 是，则进行表情绘制
			rotatedBitmap = drawEmotion(rotatedBitmap, faces);
		}
		squareBitmap(rotatedBitmap);
		srcBitmap = ImageUtils.rotateBitmap(rotatedBitmap, false, -cameraOrientation);
		srcBitmap.copyPixelsToBuffer(mGLRgbBuffer);

		if (D.I().isRecording()) {
			Bitmap recordingBitmap = Bitmap.createBitmap(rotatedBitmap, D.I().left, D.I().top, D.I().right - D.I().left, D.I().bottom - D.I().top);
			D.I().recordPic(recordingBitmap);
		}
		rotatedBitmap.recycle();
		srcBitmap.recycle();
		mGLRgbBuffer.rewind();
		// ImageUtils.encodeYUV420SP(data, mGLRgbBuffer.array(),
		// previewSize.width, previewSize.height);
	}

	/**
	 * 图片切成正方形，多余的地方留空白
	 * 
	 * @param bitmap
	 */
	public void squareBitmap(Bitmap bitmap) {
		if (D.I().top == null) {
			calculateRect(bitmap);
		}

		Canvas canvas = new Canvas(bitmap);
		Paint paint = new Paint();
		paint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
		canvas.drawRect(0, 0, D.I().right, D.I().top, paint);
		canvas.drawRect(D.I().left, D.I().bottom, bitmap.getWidth(), bitmap.getHeight(), paint);
		canvas.drawBitmap(bitmap, 0, 0, null);
		canvas.save(Canvas.ALL_SAVE_FLAG);
		canvas.restore();
	}

	/**
	 * 计算截取图片中间正方形的四边位置
	 * 
	 * @param b
	 */
	private void calculateRect(Bitmap bitmap) {
		int delt = (Math.abs(bitmap.getWidth() - bitmap.getHeight())) / 2;
		if (bitmap.getWidth() < bitmap.getHeight()) {
			D.I().left = 0;
			D.I().top = delt;
			D.I().right = bitmap.getWidth();
			D.I().bottom = bitmap.getHeight() - delt;
		} else {
			D.I().top = 0;
			D.I().left = delt;
			D.I().bottom = bitmap.getHeight();
			D.I().right = bitmap.getWidth() - delt;
		}
	}

	public void setEmotion(Emotion e) {
		this.emotion = e;
	}

	private List<MFace> detectFace(byte[] data, Size size) {
		Bitmap srcBitmap = ImageUtils.byte2Bitmap(data, size, Bitmap.Config.RGB_565);
		Bitmap rotateBitmap = ImageUtils.rotateBitmap(srcBitmap, true, cameraOrientation);

		FaceDetector.Face[] myFace = new FaceDetector.Face[NUMBER_OF_FACES];
		FaceDetector myFaceDetect = new FaceDetector(rotateBitmap.getWidth(), rotateBitmap.getHeight(), NUMBER_OF_FACES);
		// ImageUtils.saveBitmap(rotateBitmap, createImageSaveDir() +
		// "testbitmap.bmp", 100);
		int numberOfFaceDetected = myFaceDetect.findFaces(rotateBitmap, myFace);
		List<MFace> faces = null;
		if (numberOfFaceDetected > 0) {
			faces = new ArrayList<MFace>();
			for (int i = 0; i < numberOfFaceDetected; i++) {
				Face face = myFace[i];
				PointF eyesCenterPoint = new PointF();
				face.getMidPoint(eyesCenterPoint);
				float eyesDistance = face.eyesDistance();
				// Log.e("eyes distance", String.valueOf(eyesDistance));
				PointF leftEyeBitmapPoint = new PointF();
				leftEyeBitmapPoint.x = eyesCenterPoint.x - eyesDistance / 2;
				leftEyeBitmapPoint.y = eyesCenterPoint.y;

				PointF rightEyeBitmapPoint = new PointF();
				rightEyeBitmapPoint.x = eyesCenterPoint.x + eyesDistance / 2;
				rightEyeBitmapPoint.y = eyesCenterPoint.y;
				MFace mFace = new MFace(leftEyeBitmapPoint, rightEyeBitmapPoint, face);
				faces.add(mFace);
			}
		}
		return faces;
	}

	private Bitmap drawEmotion(Bitmap bitmap, List<MFace> faces) {
		if (bitmap == null) {
			return null;
		}

		if (faces == null || faces.size() == 0) {
			return bitmap;
		}

		int bitmapWidth = bitmap.getWidth();
		int bitmapHeight = bitmap.getHeight();
		Canvas canvas = new Canvas(bitmap);

		if (emotion != null) {
			// 渲染表情
			List<EmotionItem> items = emotion.render(faces, bitmap);
			if (items != null && items.size() > 0) {
				for (EmotionItem item : items) {
					canvas.drawBitmap(item.bitmap, item.matrix, null);
				}
			}
		}
		canvas.save(Canvas.ALL_SAVE_FLAG);
		canvas.restore();
		return bitmap;
	}

	private Bitmap getBitmapFromResource(int rid) {
		return BitmapFactory.decodeResource(context.getResources(), rid);
		// InputStream is = context.getResources().openRawResource(rid);
		// BitmapFactory.Options options = new BitmapFactory.Options();
		// options.inJustDecodeBounds = false;
		// options.inSampleSize = 1;
		// Bitmap bmp = BitmapFactory.decodeStream(is, null, options);
		// return bmp;
	}

	private class FaceTask extends AsyncTask<Void, Void, Void> {
		// private Bitmap bitmap;
		private byte[] data;
		private Size size;

		public FaceTask(byte[] data, Size size) {
			this.size = size;
			this.data = data;
		}

		@Override
		protected Void doInBackground(Void... params) {
			android.os.Process.setThreadPriority(THREAD_PRIORITY);
			faces = detectFace(data, size);
			return null;
		}

		@Override
		protected void onPostExecute(Void result) {
			super.onPostExecute(result);
			isDetecting = false;
		}
	}

	private String createImageSaveDir() {
		// Make sure the Pictures directory exists.
		SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy_MM_dd_hh_mm_ss");
		String date = sDateFormat.format(new java.util.Date());
		String imageSaveDir = Environment.getExternalStorageDirectory().getAbsolutePath() + "/crazyface/" + date + "/";
		File dir = new File(imageSaveDir);
		if (!dir.exists()) {
			dir.mkdirs();
		}
		return imageSaveDir;
	}

	public class MFace {
		public PointF leftEye;
		public PointF rightEye;
		public PointF mouth;
		public Face face; // 保存识别的Face

		public MFace(PointF l, PointF r, Face face) {
			leftEye = l;
			rightEye = r;
			this.face = face;
		}
	}

	public int getCameraOrientation() {
		return cameraOrientation;
	}

	public void setCameraOrientation(int cameraOrientation) {
		this.cameraOrientation = cameraOrientation;
	}
}
